package com.itheima.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/*
* 五种通知类型
*
*
* ==**环绕通知注意事项**==

1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用，进而实现原始方法调用前后同时添加通知
2. 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
3. 对原始方法的调用可以不接收返回值，通知方法设置成void即可，如果接收返回值，最好设定为Object类型
4. 原始方法的返回值如果是void类型，通知方法的返回值类型可以设置成void,也可以设置成Object
5. 由于无法预知原始方法运行后是否会抛出异常，因此环绕通知方法必须要处理Throwable异常

*
* */
@Component
@Aspect
public class MyAdvice {

    @Pointcut("execution(void com.itheima.dao.BookDao.select())") //Service所有方法加增强
    private void pt(){};

    @Pointcut("execution(int com.itheima.dao.BookDao.update())") //Service所有方法加增强
    private void pt2(){};

    @Pointcut("execution(void com.itheima.dao.BookDao.delete())") //Service所有方法加增强
    private void pt3(){};

    @Before("pt()")
    public void before(){
        System.out.println("before advice...");
    }

    @After("pt()")
    public void after(){
        System.out.println("after advice...");
    }

    @Around("pt3()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice...");
        //表示对原始操作的调用
        Integer ret = (Integer) pjp.proceed();
        System.out.println("around after advice...");
        //原始操作带有返回值此处不抛出会报错null
        return ret;
    }

    @AfterReturning("pt2()")
    public void afterReturning(){
        System.out.println("afterReturning advice...");
    }

    @AfterThrowing("pt2()")
    public void afterThrowing(){
        System.out.println("afterThrowing advice...");
    }
}
